package com.qd.system.service.msg.server.send;

import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.cdqidi.core.weixinmanager.model.MiddleUser;
import com.cdqidi.core.weixinmanager.model.TemplateMsgDetailed;
import com.cdqidi.core.weixinmanager.service.MiddleUserService;
import com.cdqidi.core.weixinmanager.service.OrgWxConfigService;
import com.cdqidi.core.weixinmanager.service.TemplateMsgDetailedService;
import com.cdqidi.core.weixinmanager.service.UserInfoService;
import com.cdqidi.exception.ApiException;
import com.jfinal.weixin.sdk.api.ApiResult;
import com.jfinal.weixin.sdk.api.TemplateData;
import com.jfinal.weixin.sdk.api.TemplateMsgApi;
import com.jfinal.wxaapp.api.WxaSubscribeMsgApi;
import com.qd.common.sys.domain.entity.msg.MsgReceiveContentDTO;
import com.qd.common.sys.domain.sendmsg.MsgContentProperty;
import com.qd.common.sys.domain.sendmsg.PersonMsg;
import com.qd.system.model.MsgReceive;
import com.qd.system.service.msg.base.MsgReceiveContentService;
import com.qd.system.service.msg.event.WxTemplateEvent;
import com.qd.system.service.msg.server.MsgProcess;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@Component
@AllArgsConstructor
@Slf4j
public class WxTemplateService {
    @Resource
    private TemplateMsgDetailedService templateMsgDetailedService;
    @Resource
    private OrgWxConfigService orgWxConfigService;
    @Resource
    private MiddleUserService middleUserService;
    @Resource
    private UserInfoService userInfoService;

    private final MsgReceiveContentService msgReceiveContentService;


    @Async
    @EventListener(classes = WxTemplateEvent.class)
    @Transactional(readOnly = true)
    public void doExec(WxTemplateEvent wxTemplateEvent) {
        PersonMsg personMsg = (PersonMsg) wxTemplateEvent.getSource();
        try {
            try {
                String appId = personMsg.getAppId();
                if (!StringUtils.hasLength(appId)) {
                    //disstatus 9 微信公众号ID为空
                    buildStatusLog(9, personMsg);
                    log.error("微信公众号ID为空");
                    return;
                }
                if (Boolean.FALSE.equals(orgWxConfigService.isExistsById(appId))) {
                    //disstatus 10 微信公众号ID不存在
                    buildStatusLog(10, personMsg);
                    log.error("微信公众号ID不存在");
                    return;
                }
                String templateShorId = personMsg.getMsgProperties().getProp("WxTempId").toString();
                if (!StringUtils.hasLength(templateShorId)) {
                    //disstatus 11 微信模版配置为空
                    buildStatusLog(11, personMsg);
                    log.error("微信模板ID为空无法发送,id:{},content:{}", personMsg.getId(), personMsg.getMsgContent().getContent());
                    return;
                }
                TemplateMsgDetailed templateMsgDetailed = buildTemplateId(templateShorId, personMsg);
                if (null == templateMsgDetailed) {
                    //disstatus 12 微信配置错误
                    return;
                }

                ApiResult jsonResult;
                String toUser;
                if (templateMsgDetailed.getTemplateType() == 0) {
                    toUser = buildToUser(personMsg, true);
                    if (null == toUser) {
                        //disstatus 13 微信关注错误
                        return;
                    }
                    jsonResult = sendWxTemplateMsg(personMsg, toUser, templateMsgDetailed);
                } else {
                    toUser = buildToUser(personMsg, false);
                    if (null == toUser) {
                        //disstatus 13 微信关注错误
                        return;
                    }
                    jsonResult = sendWxSubscribe(personMsg, toUser, templateMsgDetailed);
                }
                log.info("返回值: {}", jsonResult.getJson());
//                ApiResult jsonResult = new ApiResult("{\n" +
//                        "    \"errcode\":0,\n" +
//                        "     \"errmsg\":\"ok\",\n" +
//                        "     \"msgid\":200228332\n" +
//                        "  }");


                Long msgId = jsonResult.getLong("msgid");
                if (msgId == null) {
                    //disstatus 15 微信发送失败
                    Integer errCode = jsonResult.getInt("errcode");
                    if (null == errCode || errCode == 0) {
                        errCode = 15;
                    }
                    buildStatusLog(errCode, toUser, personMsg);
                    log.error("WEIXIN发送失败:  \ntouser=" + toUser + "  \nsendOrg=" + personMsg.getSendOrgId() + "  \nwxid=" + templateMsgDetailed.getTemplateId() + "  \nwxTempId=" + templateMsgDetailed.getTemplateIdShort() + "  \njsonResult=" + jsonResult);
                } else {
                    buildStatusLog(0, msgId + "", toUser, personMsg);
                }

            } catch (Exception e) {
                buildStatusLog(17, personMsg);
                log.error("其他异常错误", e);
            }
        } finally {
            personMsg.free();
        }
    }

    private static ApiResult sendWxTemplateMsg(PersonMsg personMsg, String toUser, TemplateMsgDetailed templateMsgDetailed) {
        TemplateData td = TemplateData.New();

        if (personMsg.getMsgReceiveCustomProperties() != null) {
            for (Map.Entry<String, MsgContentProperty> entry : personMsg.getMsgReceiveCustomProperties().getProperties().entrySet()) {
                td.add(entry.getKey(), entry.getValue().getValue(), entry.getValue().getColor());
            }
        }

        if (personMsg.getMsgReceiveDynProperties() != null) {
            for (Map.Entry<String, MsgContentProperty> entry : personMsg.getMsgReceiveDynProperties().getProperties().entrySet()) {
                td.add(entry.getKey(), entry.getValue().getValue(), entry.getValue().getColor());
            }
        }
        td.setTouser(toUser);
        td.setTemplate_id(templateMsgDetailed.getTemplateId());

        //发送模板消息，需要点击模板消息进入小程序，需要设置miniprogram
        if (personMsg.getMsgProperties().contains("appid")) {
            td.setMiniprogram((String) personMsg.getMsgProperties().getProp("appid"), personMsg.getUrl());
        } else {
            td.setUrl(personMsg.getUrl());
        }
        log.info("发送微信模板消息,内容: {}", td.build());
        return TemplateMsgApi.send(td.build());
    }

    private static ApiResult sendWxSubscribe(PersonMsg personMsg, String toUser, TemplateMsgDetailed templateMsgDetailed) {
        WxaSubscribeMsgApi.SubTemplateItem item = new WxaSubscribeMsgApi.SubTemplateItem();
        if (personMsg.getMsgReceiveCustomProperties() != null) {
            for (Map.Entry<String, MsgContentProperty> entry : personMsg.getMsgReceiveCustomProperties().getProperties().entrySet()) {
                item.put(entry.getKey(), new WxaSubscribeMsgApi.Item(entry.getValue().getValue()));
            }
        }

        if (personMsg.getMsgReceiveDynProperties() != null) {
            for (Map.Entry<String, MsgContentProperty> entry : personMsg.getMsgReceiveDynProperties().getProperties().entrySet()) {
                item.put(entry.getKey(), new WxaSubscribeMsgApi.Item(entry.getValue().getValue()));
            }
        }
        return WxaSubscribeMsgApi.send(toUser, templateMsgDetailed.getTemplateId(), item, personMsg.getUrl(),"developer");
    }

    private void buildStatusLog(int status, PersonMsg personMsg) {
        buildStatusLog(status, null, null, personMsg);
    }

    private void buildStatusLog(int status, String openId, PersonMsg personMsg) {
        buildStatusLog(status, null, openId, personMsg);
    }

    private void buildStatusLog(int status, String msgId, String openId, PersonMsg personMsg) {
        String receiveId = IdWorker.getIdStr();
        MsgReceive msgReceive = new MsgReceive();
        msgReceive.setReceiveId(receiveId);
        if (StringUtils.hasLength(msgId)) {
            msgReceive.setMsgId(msgId);
        }
        if (StringUtils.hasLength(openId)) {
            msgReceive.setOpenid(openId);
        }
        msgReceive.setSendTime(LocalDateTime.now());
        msgReceive.setMsgId(personMsg.getFromMsgId());
        msgReceive.setMsgSubId(personMsg.getFromMsgSubId());
        msgReceive.setMsgType(personMsg.getMsgContent().getType());
        msgReceive.setMsgEvent(personMsg.getMsgContent().getEvent());
        msgReceive.setFromUser(personMsg.getId());
        msgReceive.setFromUserType((int) personMsg.getClassify());
        msgReceive.setToUser(personMsg.getId());
        msgReceive.setAddTime(msgReceive.getSendTime());
        msgReceive.setStatus(status);

        MsgProcess.getInstance().addReceiveLog(msgReceive);

        buildReceiveContent(personMsg, receiveId);

    }

    public void buildReceiveContent(PersonMsg personMsg, String receiveId) {
        String templateShorId = personMsg.getMsgProperties().getProp("WxTempId").toString();
        MsgReceiveContentDTO contentLogDto = personMsg.getMsgReceiveContent();
        contentLogDto.setReceiveId(receiveId);
        contentLogDto.setTempId(templateShorId);
        contentLogDto.setAddTime(LocalDateTime.now());
        MsgProcess.getInstance().addReceiveContentLog(msgReceiveContentService.dtoToModel(contentLogDto));
    }

    /**
     * 获取用户在微信端的openid
     *
     * @param userId 用户唯一ID
     * @param appId  关注的微信公众号ID
     * @param isWx true表示模板消息 false表示小程序消息
     * @return openid
     */
    private String buildToUser(String userId, String appId, boolean isWx) {
        List<MiddleUser> list = middleUserService.getListByUserId(userId);
        if (null == list) {
            throw new ApiException("用户没有绑定关系,userId:[" + userId + "]");
        }
        MiddleUser middleUser = list.get(0);
        if (isWx) {
            String unionId = middleUser.getUnionId();
            if (!StringUtils.hasLength(unionId)) {
                throw new ApiException("获取不到unionId,userId:[" + userId + "]");
            }
            return Optional.ofNullable(userInfoService.getByUnionId(unionId, appId)).orElseThrow(() -> new ApiException("获取不到openid,unionId:[" + unionId + "],appId:[" + appId + "]")).getOpenid();
        } else {
            return middleUser.getOpenid();
        }
    }

    /**
     * 获得openid
     *
     * @param personMsg 前端数据
     * @return openid
     */
    private String buildToUser(PersonMsg personMsg, boolean isWx) {
        try {
            String userId = personMsg.getId();
            String appId = personMsg.getAppId();
            return buildToUser(userId, appId, isWx);
        } catch (ApiException e) {
            //disstatus 13 微信关注错误
            buildStatusLog(13, personMsg);
            log.error("微信关注错误", e);
            return null;
        }
    }

    /**
     * 根据templateShorId获得模板ID
     *
     * @param templateShorId templateShorId
     * @param personMsg      前端数据
     * @return templateId
     */
    private TemplateMsgDetailed buildTemplateId(String templateShorId, PersonMsg personMsg) {
        TemplateMsgDetailed template = templateMsgDetailedService.getTemplate(templateShorId, personMsg.getAppId());
        if (null == template) {
            //disstatus 12 微信配置错误
            buildStatusLog(11, personMsg);
            log.error("微信配置错误,templateShorId:{}", templateShorId);
            return null;
        }
        return template;
    }
}
